﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MemoryUtil;

namespace PlayerScannerCore.Model
{
    internal enum TextType { SectionId, CharacterId, ItemName, ItemSpecial, TechDisk, Description}

    internal class LabelReader
    {
        private readonly BaseAddress BASE_TEXT_ADDR = new BaseAddress(0x00a9cd50);

        //Text Offsets
        private const int TEXT_SECID_ARRAY = 0x120;
        private const int TEXT_CHARID_ARRAY = 0x20;
        private const int TEXT_ITEM_NAME_ARRAY = 0x04;
        private const int TEXT_ITEM_DESCRIPTION_ARRAY = 0x0c;
        private const int TEXT_ITEM_SPECIAL_ARRAY = 0x04;
        private const int TEXT_TECH_ARRAY = 0x14;

        private ProcessMemory _processMemory;
        private Dictionary<int, string> charIdCache = new Dictionary<int, string>();
        private Dictionary<int, string> sectionIdCache = new Dictionary<int, string>();
        private Dictionary<int, string> itemNameCache = new Dictionary<int, string>();
        private Dictionary<int, string> itemDescriptionCache = new Dictionary<int, string>();
        private Dictionary<int, string> itemSpecialCache = new Dictionary<int, string>();
        private Dictionary<int, string> itemTechDiskCache = new Dictionary<int, string>();

        public LabelReader(ProcessMemory processMemory)
        {
            _processMemory = processMemory;
        }

        /// <summary>
        /// Gets the text associated with the given textType at the given array index from PSO's memory. 
        /// Results are cached.
        /// </summary>
        public string GetText(TextType textType, int arrayIndex)
        {
            switch (textType)
            {
            case TextType.CharacterId:
                if (!charIdCache.ContainsKey(arrayIndex))
                    charIdCache[arrayIndex] = ReadText(TEXT_CHARID_ARRAY, arrayIndex, 50);
                return charIdCache[arrayIndex];
            case TextType.SectionId:
                if (!sectionIdCache.ContainsKey(arrayIndex))
                    sectionIdCache[arrayIndex] = ReadText(TEXT_SECID_ARRAY, arrayIndex, 50);
                return sectionIdCache[arrayIndex];
            case TextType.ItemName:
                if (!itemNameCache.ContainsKey(arrayIndex))
                    itemNameCache[arrayIndex] = ReadText(TEXT_ITEM_NAME_ARRAY, arrayIndex, 100);
                return itemNameCache[arrayIndex];
            case TextType.ItemSpecial:
                if (arrayIndex == 0)
                    return "None";
                arrayIndex &= 0x3f;
                arrayIndex += 0x277;
                if (!itemSpecialCache.ContainsKey(arrayIndex))
                    itemSpecialCache[arrayIndex] = ReadText(TEXT_ITEM_SPECIAL_ARRAY, arrayIndex, 50);
                return itemSpecialCache[arrayIndex];
            case TextType.TechDisk:
                if (!itemTechDiskCache.ContainsKey(arrayIndex))
                    itemTechDiskCache[arrayIndex] = ReadText(TEXT_TECH_ARRAY, arrayIndex, 100).Trim();
                return itemTechDiskCache[arrayIndex];
            case TextType.Description:
                if (!itemDescriptionCache.ContainsKey(arrayIndex))
                {
                    //TODO: Make sure there are spaces after periods
                    itemDescriptionCache[arrayIndex] = ReadText(TEXT_ITEM_DESCRIPTION_ARRAY, arrayIndex, 300).Replace("\n", String.Empty);
                }
                return itemDescriptionCache[arrayIndex];
            }

            return String.Empty;
        }

        private string ReadText(int textArrayOffset, int arrayIndex, int maxLength)
        {
            return _processMemory.ReadNullTerminatedString(new Pointer(BASE_TEXT_ADDR, textArrayOffset, 4 * arrayIndex, 0), maxLength);
        }
    }
}
